package com.csii.security.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.csii.core.api.Result;
import com.csii.core.constant.PublishAndSubscribeConstant;
import com.csii.core.util.oConvertUtils;
import com.csii.galaxy.studio.service.GalaxyStudioBaseService;
//import com.csii.service.PublishService;
import com.csii.user.entity.SysUser;
import com.csii.user.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.token.store.redis.JdkSerializationStrategy;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

@Slf4j
@RestController
@RequestMapping("/sys/user")
public class UserOauthController {

    @Autowired
    private RedisConnectionFactory connectionFactory;

    @Autowired
    @Lazy
    private ClientDetailsService clientDetailsService;

    @Autowired
    private GalaxyStudioBaseService galaxyStudioServiceFeign;


    private JdkSerializationStrategy serializationStrategy = new JdkSerializationStrategy();

    @Autowired
    private ISysUserService sysUserService;

//    @Autowired
//    private PublishService publishService;

    /**
     * 冻结&解冻用户
     *
     * @param jsonObject
     * @return
     */
    @RequestMapping(value = "/frozenBatch", method = RequestMethod.PUT)
    public Result<SysUser> frozenBatch(@RequestBody JSONObject jsonObject) {
        Result<SysUser> result = new Result<SysUser>();
        try {
            String ids = jsonObject.getString("ids");
            String status = jsonObject.getString("status");
            String[] arr = ids.split(",");
            List<String> clientIdList = null;
            if ("2".equals(status)){
                clientIdList = galaxyStudioServiceFeign.queryClientIdList().getResult();
            }
            for (String id : arr) {
                if (oConvertUtils.isNotEmpty(id)) {
                    SysUser updateUser = new SysUser();
                    updateUser.setStatus(Integer.parseInt(status));
                    SysUser user = sysUserService.getById(id);
                    this.sysUserService.update(updateUser,
                            new UpdateWrapper<SysUser>().lambda().eq(SysUser::getId, id));
                    if (clientIdList != null){
                        clientIdList.forEach(clientId->removeTokenAccess(user.getUsername(),clientId));
                    }
                }
            }
            //发布消息
            List<SysUser> sysUserList = sysUserService.listByIds(Arrays.asList(arr));
            //publishService.publish(PublishAndSubscribeConstant.USER_INFO_UPDATE_SYNC, sysUserList);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result.error500("操作失败" + e.getMessage());
        }
        Result.ok("操作成功!");
        return result;

    }


    private String getAuthToAccess(String name, String client_id, Set<String> scope) {
        String tempdd = null;
        Map<String, String> values = new LinkedHashMap();
        values.put("username", name);
        values.put("client_id", client_id);
        values.put("scope", OAuth2Utils.formatParameterList(new TreeSet(scope)));
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            byte[] bytes = digest.digest(values.toString().getBytes("UTF-8"));
            tempdd = String.format("%032x", new BigInteger(1, bytes));
        } catch (NoSuchAlgorithmException var4) {
            throw new IllegalStateException("MD5 algorithm not available.  Fatal (should be in the JDK).", var4);
        } catch (UnsupportedEncodingException var5) {
            throw new IllegalStateException("UTF-8 encoding not available.  Fatal (should be in the JDK).", var5);
        }
        return tempdd;
    }

    private void removeTokenAccess(String name, String client_id) {
        ClientDetails clientDetails = clientDetailsService.loadClientByClientId(client_id);
        //首先获取auth_to_access的key
        String key = getAuthToAccess(name, client_id, clientDetails.getScope());
        //再通过key获取到当前的令牌信息
        byte[] serializedKey7 = serializationStrategy.serialize("auth_to_access:" + key);

        RedisConnection conn = connectionFactory.getConnection();
        byte[] bytes = null;
        try {
            bytes = conn.get(serializedKey7);
            conn.del(serializedKey7);

        } finally {
            conn.close();
        }
        OAuth2AccessToken accessToken = serializationStrategy.deserialize(bytes,
                OAuth2AccessToken.class);
        if(accessToken==null){
            return;
        }
        //再删除令牌信息
        byte[] serializedKey = serializationStrategy.serialize("access:" + accessToken.getValue());
        byte[] serializedKey2 = serializationStrategy.serialize("access_to_refresh:" + accessToken.getValue());
        byte[] serializedKey3 = serializationStrategy.serialize("auth:" + accessToken.getValue());
        byte[] serializedKey4 = serializationStrategy.serialize("refresh:" + accessToken.getRefreshToken());
        byte[] serializedKey5 = serializationStrategy.serialize("refresh_auth:" + accessToken.getRefreshToken());
        byte[] serializedKey6 = serializationStrategy.serialize("refresh_to_access:" + accessToken.getRefreshToken());
        conn = connectionFactory.getConnection();
        try {
            conn.del(serializedKey7);
            conn.del(serializedKey);
            conn.del(serializedKey2);
            conn.del(serializedKey3);
            conn.del(serializedKey4);
            conn.del(serializedKey5);
            conn.del(serializedKey6);
        } finally {
            conn.close();
        }
    }

}
